package org.example.weboj.service.impl;

import org.example.weboj.debug.DockerDebugAdapter;
import org.example.weboj.dto.*;
import org.example.weboj.service.DebugService;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class DebugServiceImpl implements DebugService {
    
    private final Map<String, DebugSessionContext> activeSessions = new ConcurrentHashMap<>();
    
    public DebugServiceImpl() {
        // Docker调试适配器会在需要时自动创建
    }
    
    @Override
    public DebugSession startDebugSession(String sessionId, String code, String language, String input) {
        try {
            // 创建调试会话上下文
            DebugSessionContext context = new DebugSessionContext();
            context.sessionId = sessionId;
            context.language = language;
            context.code = code;
            context.input = input;
            context.state = "stopped";
            context.currentLine = 1;
            
            // 创建调试会话对象
            DebugSession session = new DebugSession();
            session.setId(sessionId);
            session.setState("stopped");
            session.setThreads(Arrays.asList(createMainThread()));
            session.setStackFrames(new ArrayList<>());
            session.setVariables(new ArrayList<>());
            session.setBreakpoints(new ArrayList<>());
            session.setCurrentLine(1);
            
            context.session = session;
            
            // 创建新的Docker调试适配器实例
            DockerDebugAdapter dockerDebugAdapter = new DockerDebugAdapter();
            
            // 启动Docker调试会话
            boolean success = dockerDebugAdapter.startDebugSession(code, input, language);
            if (!success) {
                throw new RuntimeException("Failed to start Docker debug session for language: " + language);
            }
            
            context.dockerDebugAdapter = dockerDebugAdapter;
            activeSessions.put(sessionId, context);
            
            return session;
        } catch (Exception e) {
            throw new RuntimeException("Failed to start debug session: " + e.getMessage(), e);
        }
    }
    
    @Override
    public DebugSession getDebugSession(String sessionId) {
        DebugSessionContext context = activeSessions.get(sessionId);
        if (context != null) {
            // 更新会话状态
            updateSessionFromDebugger(context);
            return context.session;
        }
        return null;
    }
    
    @Override
    public void terminateDebugSession(String sessionId) {
        DebugSessionContext context = activeSessions.remove(sessionId);
        if (context != null) {
            if (context.dockerDebugAdapter != null) {
                context.dockerDebugAdapter.terminate();
            }
            
            if (context.session != null) {
                context.session.setState("terminated");
            }
        }
    }
    
    @Override
    public void setBreakpoints(String sessionId, List<Breakpoint> breakpoints) {
        DebugSessionContext context = activeSessions.get(sessionId);
        if (context != null && context.session != null) {
            // 验证断点
            for (Breakpoint bp : breakpoints) {
                bp.setVerified(true);
            }
            context.session.setBreakpoints(breakpoints);
            
            // 设置到Docker调试器
            if (context.dockerDebugAdapter != null) {
                context.dockerDebugAdapter.setBreakpoints(breakpoints);
            }
        }
    }
    
    @Override
    public void continueExecution(String sessionId) {
        DebugSessionContext context = activeSessions.get(sessionId);
        if (context != null) {
            context.state = "running";
            context.session.setState("running");
            
            if (context.dockerDebugAdapter != null) {
                context.dockerDebugAdapter.continueExecution();
            }
        }
    }
    
    @Override
    public void stepOver(String sessionId) {
        DebugSessionContext context = activeSessions.get(sessionId);
        if (context != null) {
            context.state = "running";
            context.session.setState("running");
            
            if (context.dockerDebugAdapter != null) {
                context.dockerDebugAdapter.stepOver();
            }
        }
    }
    
    @Override
    public void stepInto(String sessionId) {
        DebugSessionContext context = activeSessions.get(sessionId);
        if (context != null) {
            context.state = "running";
            context.session.setState("running");
            
            if (context.dockerDebugAdapter != null) {
                context.dockerDebugAdapter.stepInto();
            }
        }
    }
    
    @Override
    public void stepOut(String sessionId) {
        DebugSessionContext context = activeSessions.get(sessionId);
        if (context != null) {
            context.state = "running";
            context.session.setState("running");
            
            if (context.dockerDebugAdapter != null) {
                context.dockerDebugAdapter.stepOut();
            }
        }
    }
    
    @Override
    public void pauseExecution(String sessionId) {
        DebugSessionContext context = activeSessions.get(sessionId);
        if (context != null) {
            context.state = "stopped";
            context.session.setState("stopped");
        }
    }
    
    @Override
    public List<StackFrame> getStackTrace(String sessionId) {
        DebugSessionContext context = activeSessions.get(sessionId);
        if (context != null && context.dockerDebugAdapter != null) {
            try {
                List<StackFrame> stackFrames = context.dockerDebugAdapter.getStackTrace();
                context.session.setStackFrames(stackFrames);
                return stackFrames;
            } catch (Exception e) {
                System.err.println("Error getting stack trace: " + e.getMessage());
                return createMockStackTrace(context);
            }
        }
        return new ArrayList<>();
    }
    
    @Override
    public List<DebugVariable> getVariables(String sessionId, int frameId) {
        DebugSessionContext context = activeSessions.get(sessionId);
        if (context != null && context.dockerDebugAdapter != null) {
            try {
                List<DebugVariable> variables = context.dockerDebugAdapter.getVariables();
                context.session.setVariables(variables);
                return variables;
            } catch (Exception e) {
                System.err.println("Error getting variables: " + e.getMessage());
                return createMockVariables(context);
            }
        }
        return new ArrayList<>();
    }
    
    @Override
    public String evaluateExpression(String sessionId, String expression) {
        DebugSessionContext context = activeSessions.get(sessionId);
        if (context != null && context.dockerDebugAdapter != null) {
            try {
                return context.dockerDebugAdapter.evaluateExpression(expression);
            } catch (Exception e) {
                return "Error: " + e.getMessage();
            }
        }
        return "No active session";
    }
    
    // 私有方法
    
    private void updateSessionFromDebugger(DebugSessionContext context) {
        if (context.dockerDebugAdapter != null) {
            try {
                context.currentLine = context.dockerDebugAdapter.getCurrentLine();
                context.session.setCurrentLine(context.currentLine);
            } catch (Exception e) {
                System.err.println("Error updating session from debugger: " + e.getMessage());
            }
        }
    }
    
    private DebugSession.Thread createMainThread() {
        DebugSession.Thread thread = new DebugSession.Thread();
        thread.setId(1);
        thread.setName("Main Thread");
        return thread;
    }
    
    private List<StackFrame> createMockStackTrace(DebugSessionContext context) {
        List<StackFrame> stackFrames = new ArrayList<>();
        StackFrame frame = new StackFrame();
        frame.setId(1);
        frame.setName("main");
        frame.setSource(getFileName(context.language));
        frame.setLine(context.currentLine);
        frame.setColumn(1);
        stackFrames.add(frame);
        
        context.session.setStackFrames(stackFrames);
        return stackFrames;
    }
    
    private List<DebugVariable> createMockVariables(DebugSessionContext context) {
        List<DebugVariable> variables = new ArrayList<>();
        
        // 根据语言创建不同的变量示例
        if ("python".equalsIgnoreCase(context.language)) {
            addPythonVariables(variables);
        } else if ("java".equalsIgnoreCase(context.language)) {
            addJavaVariables(variables);
        } else if ("cpp".equalsIgnoreCase(context.language) || "c".equalsIgnoreCase(context.language)) {
            addCppVariables(variables);
        }
        
        context.session.setVariables(variables);
        return variables;
    }
    
    private void addPythonVariables(List<DebugVariable> variables) {
        DebugVariable var1 = new DebugVariable();
        var1.setName("__name__");
        var1.setValue("'__main__'");
        var1.setType("str");
        var1.setExpandable(false);
        variables.add(var1);
        
        DebugVariable var2 = new DebugVariable();
        var2.setName("locals()");
        var2.setValue("{...}");
        var2.setType("dict");
        var2.setExpandable(true);
        variables.add(var2);
    }
    
    private void addJavaVariables(List<DebugVariable> variables) {
        DebugVariable var1 = new DebugVariable();
        var1.setName("args");
        var1.setValue("String[0] {...}");
        var1.setType("String[]");
        var1.setExpandable(true);
        variables.add(var1);
    }
    
    private void addCppVariables(List<DebugVariable> variables) {
        DebugVariable var1 = new DebugVariable();
        var1.setName("argc");
        var1.setValue("1");
        var1.setType("int");
        var1.setExpandable(false);
        variables.add(var1);
        
        DebugVariable var2 = new DebugVariable();
        var2.setName("argv");
        var2.setValue("char** {...}");
        var2.setType("char**");
        var2.setExpandable(true);
        variables.add(var2);
    }
    
    private String getFileName(String language) {
        return switch (language.toLowerCase()) {
            case "python" -> "main.py";
            case "java" -> "Main.java";
            case "cpp", "c" -> "main.cpp";
            case "javascript" -> "main.js";
            default -> "main.txt";
        };
    }
    
    // 内部类：调试会话上下文
    private static class DebugSessionContext {
        String sessionId;
        String language;
        String code;
        String input;
        String state;
        int currentLine;
        DebugSession session;
        DockerDebugAdapter dockerDebugAdapter;
    }
}